using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using HomeDms.Properties;
using System.Data.Linq;
using System.Reflection;
using System.Diagnostics;
using HomeDMSDomain;
using System.Threading;
using HomeDmsUtils;
using System.Data.SqlServerCe;
using System.Deployment.Application;

namespace HomeDms
{
    public partial class DocumentListForm : Form
    {
        private BindnFindObjectsDataContext _currentContext;
        private Dictionary<string, ListSortDirection> _columnSorting;
        private int _currentSelectionIndex = 0;
        private bool _isRefreshing;
        
        public DocumentListForm()
        {
            ChangeAppUILanguage(false);
            InitializeComponent();
            _columnSorting = new Dictionary<string, ListSortDirection>();
            foreach (DataGridViewColumn item in documentsGridView.Columns)
            {
                if (item.SortMode != DataGridViewColumnSortMode.NotSortable)
                {
                    _columnSorting.Add(item.Name, ListSortDirection.Ascending);
                }
            }
            documentsGridView.SelectionChanged += new EventHandler(documentsGridView_SelectionChanged);
        }

        void documentsGridView_SelectionChanged(object sender, EventArgs e)
        {
            if (documentsGridView.SelectedRows.Count > 0 && !_isRefreshing)
            {
                _currentSelectionIndex = documentsGridView.SelectedRows[0].Index;
            }
        }

        private void DocumentListForm_Shown(object sender, EventArgs e)
        {
            if (!Settings.Default.SkipStartScreen)
                using (ActionsForm af = new ActionsForm())
                {
                    af.ShowDialog(this);
                }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (AboutForm af = new AboutForm())
                af.ShowDialog(this);
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (PreferencesForm pf = new PreferencesForm())
            {
                DialogResult r = pf.ShowDialog(this);
                if (r == DialogResult.Retry)
                    ChangeAppUILanguage(true);
            }
        }

        private void ChangeAppUILanguage(bool fromTheMiddleOfWork)
        {
            if (fromTheMiddleOfWork) // in the middle of work...
            {
                RestartingDueToUILanguageChange = true;
                Application.Restart();
            }
            switch (Settings.Default.UILanguage)
            {
                case 0: Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
                    break;
                case 1: Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ru-RU");
                    break;
                case 2: Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("he-IL");
                    break;
            }
        }

        private static DocumentListForm theDocumentListForm = null;

        public static DocumentListForm TheDocumentListForm
        {
            get
            {
                return theDocumentListForm;
            }
        }

        internal bool RestartingDueToUILanguageChange = false;

        private void DocumentListForm_Load(object sender, EventArgs e)
        {
            StartCheckUpdates();
            theDocumentListForm = this;
            toolStripButton2.Visible = Program.CmdLine.Contains<string>("/developer");
            if (string.IsNullOrEmpty(Properties.Settings.Default.LastOpenedBase))
            {
                if (!FirstTime())
                    return;
            }
            else
            {
                BindnFindObjectsDataContext.CurrentDB = Properties.Settings.Default.LastOpenedBase;
                Text = "Bind`n`find - " + BindnFindObjectsDataContext.CurrentDB;
                _currentContext = BindnFindObjectsDataContext.Instance;
            }
            RefreshData();
        }

        private bool FirstTime()
        {
            using (FirstTimeForm ftf = new FirstTimeForm())
            {
                switch (ftf.ShowDialog(this))
                {
                    case DialogResult.Cancel:
                        Application.Exit();
                        return false;                        
                    case DialogResult.OK:
                        if (!NewDatabase(ftf.DBPath))
                        {
                            Localizer.MsgBox(this, "Essential parameters not set. Bind`n`find will exit now.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            Application.Exit();
                            return false;
                        }
                        return true;
                    case DialogResult.Retry:
                        Application.Restart();
                        return false;
                }
                return true;
            }
        }

        ApplicationDeployment appDep;

        private void StartCheckUpdates()
        {
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                appDep = ApplicationDeployment.CurrentDeployment;
                appDep.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(ad_CheckForUpdateCompleted);                
                appDep.CheckForUpdateAsync();
            }
        }

        void ad_CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e)
        {
            if (e.UpdateAvailable)
            {
                UpdateApp();
            }
        }

        private void UpdateApp()
        {
            if (Localizer.MsgBox(this, "New version of Bind`n`find is available. Do you want to install it now? Upon complete application will be restarted.",
                "Automatic update", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
            {
                Cursor = Cursors.WaitCursor;
                appDep.Update();
                Cursor = Cursors.Default;
                Application.Restart();
            }
        }

        private void RefreshData()
        {
            try
            {
                if (_currentContext != null)
                {

                    _isRefreshing = true;
                    documentsBindingSource.Clear();
                    documentsBindingSource.ResetBindings(false);
                    _currentContext = BindnFindObjectsDataContext.Instance;

                    if (_currentContext.Documents.Count<Document>() >= 5000)
                    {
                        newToolStripButton.Enabled = false;
                    }
                    else
                    {
                        newToolStripButton.Enabled = true;
                    }

                    documentsBindingSource.DataSource = _currentContext.Documents.ToList<Document>();
                    documentsBindingSource.ResetBindings(false);

                    if (_currentSelectionIndex >= 0 && documentsGridView.Rows.Count > 0 && _currentSelectionIndex < documentsGridView.Rows.Count)
                    {
                        documentsGridView.Rows[_currentSelectionIndex].Selected = true;
                    }
                    _isRefreshing = false;
                    if (!timer1.Enabled)
                        timer1.Enabled = true;
                }
            }
            catch (Exception ex)
            {
                DialogResult res = Localizer.MsgBox(this, 
@"Error occured when accessing the database. The reason was:\n{0}
\n\nClick Yes if you would you like to create new database.\n
Click No if you wish to open another existing database from disk.\n
Click Cancel to exit the program", "Error", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Error, ex.Message);                  
                switch (res)
                {
                    case DialogResult.Yes:
                        if (!NewDatabase(GetNewDatabasePath()))
                        {
                            Localizer.MsgBox(this, "Database was not created. Bind`n`find will exit now.", "Create new database", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            Application.Exit();
                        }
                        break;
                    case DialogResult.No:
                        OpenDatabase();
                        break;
                    default:
                        throw;
                }
            }
        }
        
        private void createDBDialog_FileOk(object sender, CancelEventArgs e)
        {
            e.Cancel = File.Exists(createDBDialog.FileName);
            if (e.Cancel)
                Localizer.MsgBox(this, "File '{0}' is already exists and may contain your database with documents. Please use another database name, or delete or rename existing file manually.",
                    "Create new database", MessageBoxButtons.OK, MessageBoxIcon.Warning, createDBDialog.FileName);
        }

        private string GetNewDatabasePath()
        {
            createDBDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            if (createDBDialog.ShowDialog(this) == DialogResult.OK)
                return createDBDialog.FileName;
            else
                return null;
        }

        private void editToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenDocumentForm(false, DocumentForm.Layouts.Edit);
        }

        private void changeCurrentUserToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void backupToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void restoreDatabaseToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenDocumentForm(true, DocumentForm.Layouts.Edit);
        }

        private void deleteDocumentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DeleteDocument();
        }

        private void findToolStripButton_Click(object sender, EventArgs e)
        {
            if (sender is ToolStripMenuItem)
                findToolStripButton.Checked = findDocumentToolStripMenuItem.Checked;
            else
                findDocumentToolStripMenuItem.Checked = findToolStripButton.Checked;
            splitContainer.Panel1Collapsed = !findToolStripButton.Checked;
            if (splitContainer.Panel1Collapsed)
            {
                findDocumentToolStripMenuItem.Text = "Find Document";
                RefreshData();
            }
            else
            {
                findDocumentToolStripMenuItem.Text = "Clear Find Document";
                findPanelControl1.ClearSearch();
            }
        }

        void findPanelControl1_SearchExecuted(object sender, EventArgs e)
        {
            documentsBindingSource.DataSource = findPanelControl1.SearchResult;            
            documentsBindingSource.ResetBindings(false);
        }

        private void newToolStripButton_Click(object sender, EventArgs e)
        {
            OpenDocumentForm(true, DocumentForm.Layouts.Edit);
        }

        private void OpenDocumentForm(bool forAdd, DocumentForm.Layouts layout)
        {
            using (DocumentForm dForm = new DocumentForm())
            {
                //dForm.DocumentsUpdated += new EventHandler(dForm_DocumentsUpdated);

                if (!forAdd)
                {
                    Document doc = documentsBindingSource.Current as Document;
                    if (doc != null)
                    {
                        dForm.DocumentId = doc.document_id;
                    }
                }
                dForm.LayoutMode = layout;
                dForm.DocumentCollectionChanged += new EventHandler(dForm_DocumentCollectionChanged);

                dForm.ShowDialog(this);
            }
        }

        void dForm_DocumentCollectionChanged(object sender, EventArgs e)
        {
            RefreshData();
        }

        void dForm_DocumentsUpdated(object sender, EventArgs e)
        {
            RefreshData();
        }

        private void mnuNewDB_Click(object sender, EventArgs e)
        {
            // TODO: Save current context
            if (!NewDatabase(GetNewDatabasePath()))
            {
                // TODO: restore previous context
            }
        }

        private bool NewDatabase(string path)
        {
            if (string.IsNullOrEmpty(path))
                return false;
            BindnFindObjectsDataContext.CurrentDB = path;
            Text = "Bind`n`find - " + BindnFindObjectsDataContext.CurrentDB;
            _currentContext = BindnFindObjectsDataContext.Instance;
            try
            {
                _currentContext.CreateDatabase();
            }
            catch (SqlCeException e)
            {
                if (e.NativeError != 25501)
                {
                    Localizer.MsgBox(this, e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
            }
            _currentContext.PrefillDatabaseWithData();
            Properties.Settings.Default.LastOpenedBase = path;
            Properties.Settings.Default.Save();
            RefreshData();
            return true;
        }

        private void mnuOpenDB_Click(object sender, EventArgs e)
        {
            OpenDatabase();
        }

        private void OpenDatabase()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "DB File|*.sdf";
            DialogResult res = dlg.ShowDialog(this);
            if (res == DialogResult.OK)
            {
                BindnFindObjectsDataContext.CurrentDB = dlg.FileName;
                Text = "Bind`n`find - " + BindnFindObjectsDataContext.CurrentDB;
                _currentContext = BindnFindObjectsDataContext.Instance;
                RefreshData();
                Properties.Settings.Default.LastOpenedBase = dlg.FileName;
                Properties.Settings.Default.Save();
            }
        }

        private void mnuToolsDeleteDB_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "DB File|*.sdf";
            DialogResult res = dlg.ShowDialog(this);
            if (res == DialogResult.OK)
            {
                BindnFindObjectsDataContext.CurrentDB = dlg.FileName;
                Text = "Bind`n`find - " + BindnFindObjectsDataContext.CurrentDB;
                _currentContext = BindnFindObjectsDataContext.Instance;
                _currentContext.DeleteDatabase();
                Properties.Settings.Default.LastOpenedBase = string.Empty;
                Properties.Settings.Default.Save();
            }
        }

        private void EditStripButton1_Click(object sender, EventArgs e)
        {
            OpenDocumentForm(false, DocumentForm.Layouts.Edit);
        }

        private void ViewToolStripButton_Click(object sender, EventArgs e)
        {
            OpenDocumentForm(false, DocumentForm.Layouts.View);
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            GenerateTestContent();
        }

        private static void GenerateTestContent()
        {
            for (int i = 0; i < 5000; i++)
            {
                BindnFindObjectsDataContext db = BindnFindObjectsDataContext.Instance;
                Document doc = new Document();
                doc.Name = "Test " + i.ToString();
                db.Documents.InsertOnSubmit(doc);

                Page p1 = new Page();
                Page p2 = new Page();
                Page p3 = new Page();
                Page p4 = new Page();
                Page p5 = new Page();
                p1.Name = "Page 1";
                Image img1 = Properties.Resources.KroKol;
                p1.Image = img1;
                p1.IsDefault = false;
                doc.Pages.Add(p1);
                p1.Document = doc;
                db.Pages.InsertOnSubmit(p1);
                p2.Name = "Page 2";
                Image img2 = Properties.Resources.KroKol;
                p2.Image = img2;
                p2.IsDefault = false;
                doc.Pages.Add(p2);
                p2.Document = doc;
                db.Pages.InsertOnSubmit(p2);
                p3.Name = "Page 3";
                Image img3 = Properties.Resources.KroKol;
                p3.Image = img3;
                p3.IsDefault = false;
                doc.Pages.Add(p3);
                p3.Document = doc;
                db.Pages.InsertOnSubmit(p3);
                p4.Name = "Page 4";
                Image img4 = Properties.Resources.KroKol;
                p4.Image = img4;
                p4.IsDefault = false;
                doc.Pages.Add(p4);
                p4.Document = doc;
                db.Pages.InsertOnSubmit(p4);
                p5.Name = "Page 5";
                Image img5 = Properties.Resources.KroKol;
                p5.Image = img5;
                p5.IsDefault = false;
                doc.Pages.Add(p5);
                p5.Document = doc;
                db.Pages.InsertOnSubmit(p5);

                //db.pages.InsertOnSubmit(p);
                db.SubmitChanges();
                img1.Dispose();
                img2.Dispose();
                img3.Dispose();
                img4.Dispose();
                img5.Dispose();

            }
        }

        private void deleteToolStripButton_Click(object sender, EventArgs e)
        {
            DeleteDocument();
        }

        private void DeleteDocument()
        {
            if (documentsBindingSource.Current == null)
                return;
            DialogResult res = Localizer.MsgBox(this, "Are you sure you want to delete this document? \nAfter the removal it will disappear from the database forever.", 
                "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
            if (res == DialogResult.Yes)
            {
                Document doc = documentsBindingSource.Current as Document;
                if (doc != null)
                {
                    try
                    {
                        _currentContext.Documents.DeleteOnSubmit(doc);
                        _currentContext.SubmitChanges();
                        _currentContext.Dispose();
                        _currentContext = BindnFindObjectsDataContext.Instance;
                        RefreshData();
                    }
                    catch (Exception ex)
                    {
                        Localizer.MsgBox(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }

        private void bindingNavigatorDeleteItem_Click(object sender, EventArgs e)
        {
            DeleteDocument();
        }

        private void viewDocumentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenDocumentForm(false, DocumentForm.Layouts.View);
        }

        private void homeDMSOnTheWebToolStripMenuItem_Click(object sender, EventArgs e)
        {
            process1.Start();
        }

        private void DocumentListForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_currentContext != null)
            {
                
            }
        }

        private void documentsGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridViewColumn item = documentsGridView.Columns[e.ColumnIndex];
            if (_columnSorting.ContainsKey(item.Name))
            {
                IEnumerable<Document> docs = documentsBindingSource.DataSource as IEnumerable<Document>;
                if (docs != null)
                {
                    
                    if (_columnSorting[item.Name] == ListSortDirection.Ascending)
                    {
                        documentsBindingSource.DataSource = docs.OrderBy(d => d.GetType().GetProperty(item.DataPropertyName).GetValue(d,new object[] {}));
                        _columnSorting[item.Name] = ListSortDirection.Descending;
                        item.HeaderCell.SortGlyphDirection = SortOrder.Ascending;
                    }
                    else
                    {
                        documentsBindingSource.DataSource = docs.OrderByDescending(d => d.GetType().GetProperty(item.DataPropertyName).GetValue(d,new object[] {}));
                        _columnSorting[item.Name] = ListSortDirection.Ascending;
                        item.HeaderCell.SortGlyphDirection = SortOrder.Descending;
                    }
                    documentsBindingSource.ResetBindings(false);
                }
            }
        }

        private void documentsGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0)
                viewDocumentToolStripMenuItem_Click(sender, e);    
        }

        private void documentsGridView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                viewDocumentToolStripMenuItem_Click(sender, EventArgs.Empty);
        }

        private void findPanelControl1_SearchCleared(object sender, EventArgs e)
        {
            RefreshData();
            documentsBindingSource.ResetBindings(false);
        }

        private void documentsGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            Document d = documentsBindingSource[e.RowIndex] as Document;
            if (d == null)
                return;
            if (DateTime.Now > d.To.GetValueOrDefault(DateTime.MaxValue))
            {
                e.CellStyle.Font = new Font(e.CellStyle.Font, FontStyle.Bold);
                e.CellStyle.ForeColor = Color.Red;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            DateTime now = DateTime.Now;
            var q = from d in _currentContext.Documents where now > d.To select d;
            docExpiredStripLabel.Visible = q.Count<Document>() > 0;
            docExpiredStripSeparator.Visible = docExpiredStripLabel.Visible;
            timer1.Enabled = true;

        }

        private void docExpiredStripLabel_Click(object sender, EventArgs e)
        {
            if (!showExpiredStripButton.Checked)
                showExpiredStripButton.PerformClick();
        }


        private void showExpiredStripButton_Click(object sender, EventArgs e)
        {
            if (showExpiredStripButton.Checked)
            {
                DateTime now = DateTime.Now;
                var q = from d in _currentContext.Documents where now > d.To select d;
                List<Document> expired = q.ToList<Document>();
                documentsBindingSource.DataSource = expired;
                documentsBindingSource.ResetBindings(false);
            }
            else
            {
                RefreshData();
                documentsBindingSource.ResetBindings(false);
            }
        }

        private void toolStripMenuItem3_Click(object sender, EventArgs e)
        {
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                appDep = ApplicationDeployment.CurrentDeployment;
                Cursor = Cursors.WaitCursor;
                try
                {
                    if (appDep.CheckForUpdate())
                    {
                        UpdateApp();
                    }
                    else
                    {
                        Localizer.MsgBox(this, "No new versions found. Your version is up to date.", 
                            "Automatic update", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
                finally
                {
                    Cursor = Cursors.Default;
                }
            }
        }
    }
}
